#include <fcntl.h>
#include <router/RouterControlServer.h>
#include <router/RouterClient.h>
#include <router/RouterServer.h>
#include <iostream>

RouterControlServer::RouterControlServer(uint16_t port):
    tcp_server(port),
    App(get_sockfd())
{ }


std::pair<response,bool> RouterControlServer::get_response(uint32_t req_id, int timeout_sec){
    return received_response.get(req_id, timeout_sec);
}

// message_hander处理的是 其他应用、路由服务器发送过来的消息，一般是命令，也会收到响应
void RouterControlServer::message_hander(message msg)
{
    if (msg.get_router_info().message_type == MessageType::RESPONSE){
        response resp(msg);
        received_response.put(resp.get_head().req_id, resp);
        return;
    }

    if (msg.get_router_info().message_type != MessageType::REQUEST){
        return;
    }
    
    response resp = hand_request(msg);
    send_message_to(resp, resp.get_router_info().to);
}

void RouterControlServer::fd_hander()
{
    while (true)
    {
        int client = accept();
        if (client < 0) {
            if (errno == EAGAIN || errno == EWOULDBLOCK) {
                // 没有连接请求需要处理，可以做一些其他的事情
                // ...
            } else {
                // 出现错误，需要进行错误处理
                // ...
            }
            break;
        } 
        else {
            auto [msg, is_valid] = message::read_message_from(client);
            if (is_valid == false || msg.get_router_info().message_type != MessageType::REQUEST){
                close(client);
                return;
            }
            request req(msg);
            response resp = hand_request(msg);
            message::write_message_to(resp, client);
            std::this_thread::sleep_for(std::chrono::seconds(1));
            close(client);
        }
    }



}

bool RouterControlServer::login(uint32_t user, uint32_t host, std::string_view password)
{
    router_client.set_user_host(user, host);
    this->set_sender({user, host, RouterClient::CONTROLLER_ID});

    request req = RouterRequest::login(password);
    uint32_t req_id = req.get_head().req_id;

    send_message_to(req, RouterServer::SERVER_ENDPOINT);
    auto[resp, is_valid] = get_response(req_id, timeout_sec);
    if (is_valid == false || resp.get_head().code != response_code::SUCCESS)
        return false;

    return true;
}

void RouterControlServer::notify_new_client_connect(std::shared_ptr<VirtualServer> server, std::shared_ptr<TrueClient> client){
    uint32_t app_id = router_client.register_app(client);
    create_virtual_client_data req_data {router_client.get_user_id(), router_client.get_host_id(), server->get_rule_id(), app_id};

    request req = RouterRequest::create_virtual_client(req_data);
    uint32_t req_id = req.get_head().req_id;

    forward_rule rule = forwardtable.get_rule(server->get_rule_id());
    Endpoint receiver {rule.dst_user, rule.dst_host, RouterClient::CONTROLLER_ID};
    send_message_to(req, receiver);
    auto[resp, is_valid] = get_response(req_id, timeout_sec);
    if (is_valid == false || resp.get_head().code != response_code::SUCCESS){
        router_client.unregister_app(client);
        return;
    }
    
    forwardtable.add_apps(server->get_rule_id(), client);
    uint32_t dst_app_id = any_cast<uint32_t>(resp.get_body());
    client->set_receiver({rule.dst_user, rule.dst_host, dst_app_id});
}

void RouterControlServer::notify_true_client_disconnect(std::shared_ptr<TrueClient> client){

}

void RouterControlServer::notify_virtual_client_disconnect(std::shared_ptr<VirtualClient> client){

}


response RouterControlServer::hand_request(request req){
    switch (req.get_head().op)
    {
        using enum request_op;
    case CREATE_FORWARD_RULE:{
        forward_rule body = any_cast<forward_rule>(req.get_body());
        if (forwardtable.contain_rule(body))
            return RouterResponse::make_response(req, response_code::SUCCESS);
            
        uint32_t rule_id = forwardtable.put_rule(body);
        create_output_forward_rule_data rule_data {router_client.get_user_id(), router_client.get_host_id(), rule_id, body.target_ip, body.target_port};
        request req2 = RouterRequest::create_output_forward_rule(rule_data);
        uint32_t req_id = req2.get_head().req_id;
        Endpoint receiver {body.dst_user, body.dst_host, RouterClient::CONTROLLER_ID};
        send_message_to(req2, receiver);
        auto[resp, is_valid] = get_response(req_id, timeout_sec);


        if (is_valid == false){
            forwardtable.rm_rule(rule_id);
            return RouterResponse::make_response(req, response_code::FAILED);
        }

        std::shared_ptr<VirtualServer> vserver = std::make_shared<VirtualServer>(body.src_port, rule_id);
        int flags = fcntl(vserver->get_sockfd(), F_GETFL, 0);
        fcntl(vserver->get_sockfd(), F_SETFL, flags | O_NONBLOCK);

        uint32_t app_id = router_client.register_app(vserver);
        forwardtable.add_apps(rule_id, vserver);
        return RouterResponse::make_response(req, response_code::SUCCESS);
    }

    case CRAETE_OUTPUT_FORWARD_RULE:{
        create_output_forward_rule_data body = any_cast<create_output_forward_rule_data>(req.get_body());
        output_forward_rule rule;
        rule.user = body.user;
        rule.host = body.host;
        rule.rule_key = body.rule_id;
        if (output_forwardtable.contain_rule(rule))
            return RouterResponse::make_response(req, response_code::SUCCESS);

        ip_port addr;
        addr.ip = body.target_ip;
        addr.port = body.target_port;
        output_forwardtable.put_rule(rule, addr);

        return RouterResponse::make_response(req, response_code::SUCCESS);
    } 

    case CREATE_VIRTUAL_CLIENT:{
        create_virtual_client_data body = any_cast<create_virtual_client_data>(req.get_body());
        output_forward_rule rule {body.user, body.host, body.rule_id};
        ip_port addr = output_forwardtable.get_ip_port(rule);
        std::shared_ptr<VirtualClient> client = std::make_shared<VirtualClient>(addr.ip, addr.port);

        int flags = fcntl(client->get_sockfd(), F_GETFL, 0);
        fcntl(client->get_sockfd(), F_SETFL, flags | O_NONBLOCK);

        uint32_t app_id = router_client.register_app(client);
        output_forwardtable.add_apps(rule, client);
        client->set_receiver({body.user, body.host, body.app_id});
        app_id = htonl(app_id);
        return RouterResponse::make_response(req, response_code::SUCCESS, std::span<char const>(reinterpret_cast<char*>(&app_id), sizeof(app_id)));
    }
    }

    return RouterResponse::make_response(req, response_code::UNKNOWN_OP);
}

